\defmodule{JDBCManager}

This class provides some facilities to connect to a SQL database and to
retrieve data stored in it.
JDBC provides a standardized interface for accessing a database
independently of a specific database management system (DBMS).
The user of JDBC must create a \class{Connection} object
used to send SQL queries to the underlying DBMS, but
the creation of the connection adds a DBMS-specific portion
in the application.
This class helps the developer in moving the DBMS-specific
information out of the source code by storing it in
a properties file.  The methods in this class can
read such a properties file and establish the JDBC connection.
The connection can be made by using a \class{DataSource} obtained
through a JNDI server, or by a JDBC URI associated with a
driver class.
Therefore, the properties used to connect to the
database must be a JNDI name (\texttt{jdbc.jndi-name}),
or a driver to load
(\texttt{jdbc.driver}) with the URI of a database (\texttt{jdbc.uri}).
\begin{vcode}

   jdbc.driver=com.mysql.jdbc.Driver\\
   jdbc.uri=jdbc:mysql://mysql.iro.umontreal.ca/database?user=foo&password=bar
\end{vcode}

The connection is established using the
\method{connectToDatabase}{(Properties)}
method.  Shortcut methods are also available to read the
properties from a file or a resource before establishing the connection.
This class also provides shortcut methods to read data from a database
and to copy the data into Java arrays.

\bigskip\hrule

\begin{code}\begin{hide}
/*
 * Class:        JDBCManager
 * Description:  Interface to access databases
 * Environment:  Java
 * Software:     SSJ 
 * Copyright (C) 2001  Pierre L'Ecuyer and Universite de Montreal
 * Organization: DIRO, Universite de Montreal
 * @author       
 * @since

 * SSJ is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License (GPL) as published by the
 * Free Software Foundation, either version 3 of the License, or
 * any later version.

 * SSJ is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * A copy of the GNU General Public License is available at
   <a href="http://www.gnu.org/licenses">GPL licence site</a>.
 */
\end{hide}
package umontreal.iro.lecuyer.util;
\begin{hide}
import java.io.*;
import java.net.URL;
import java.sql.*;
import javax.sql.DataSource;
import java.util.Properties;
import javax.naming.*;
\end{hide}

public class JDBCManager\begin{hide} {
\end{hide}\end{code}
\subsubsection*{Methods}
\begin{code}

   public static Connection connectToDatabase (Properties prop)
            throws SQLException \begin{hide} {
      Connection connection = null;
      String jndiName;
        
      if ((jndiName = prop.getProperty ("jdbc.jndi-name")) != null)
      {
         try
         {
            InitialContext context = new InitialContext();
            connection = ((DataSource) context.lookup (jndiName)).getConnection();
         }
         catch (NamingException e)
         {
            throw new IllegalArgumentException
                  ("The jdbc.jndi-name property refers to the invalid name " + jndiName);
         }
      }
      else
      {
         String driver = prop.getProperty ("jdbc.driver");
         String uri = prop.getProperty ("jdbc.uri");
         if (uri != null)
         {
            if (driver != null) {
               try
               {
                  Class driverClass = Class.forName (driver);
                  if (!Driver.class.isAssignableFrom (driverClass))
                     throw new IllegalArgumentException
                        ("The driver name " + driver +
                     " does not correspond to a class implementing the java.sql.Driver interface");
                  // Needed by some buggy drivers
                  driverClass.newInstance();
               }
               catch (ClassNotFoundException cnfe) {
                  throw new IllegalArgumentException ("Could not find the driver class " + driver);
               }
               catch (IllegalAccessException iae) {
                  throw new IllegalArgumentException
                        ("An illegal access prevented the instantiation of driver class " + driver);
               }
               catch (InstantiationException ie) {
                  throw new IllegalArgumentException
                        ("An instantiation exception prevented the instantiation of driver class " + driver +
                                ": " + ie.getMessage());
               }
            }
            connection = DriverManager.getConnection (uri);
         }
         else
         {
            throw new IllegalArgumentException
                ("The jdbc.driver and jdbc.uri properties must be given if jdbc.jndi-name is not set");
         }            
      }

      return connection;
   }\end{hide}
\end{code}
\begin{tabb}
   Connects to the database using the properties \texttt{prop} and returns the 
   an object representing the connection.
   The properties stored in \texttt{prop} must be a JNDI name
    (\texttt{jdbc.jndi-name}), or the name of a driver
   (\texttt{jdbc.driver}) to load and the URI of the database (\texttt{jdbc.uri}).
   When a JNDI name is given, this method constructs a
   context using the nullary constructor of \class{InitialContext},
   uses the context to get a \class{DataSource} object,
   and uses the data source to obtain a connection.
    This method assumes that JNDI is configured correctly;
   see the class \class{InitialContext} for more information about configuring
   JNDI.
   If no JNDI name is specified, the method looks for a JDBC URI.
   If a driver class name is specified along with the URI, the corresponding driver
   is loaded and registered with the JDBC \class{DriverManager}.
   The driver manager is then used to obtain the connection using the URI.
 This method throws
   an \class{SQLException} if the connection failed and an
  \class{IllegalArgumentException}
   if the properties do not contain the required values.
\end{tabb}
\begin{htmlonly}
   \param{prop}{the properties to connect to the database.}
   \return{the connection to the database.}
   \exception{SQLException}{if the connection failed.}
   \exception{IllegalArgumentException}{if the properties do not contain the require values.}
\end{htmlonly}
\begin{code}

   public static Connection connectToDatabase (InputStream is)
            throws IOException, SQLException \begin{hide} {
      Properties prop = new Properties();
        
      prop.load (is);
        
      return connectToDatabase (prop);
   }\end{hide}
\end{code}
\begin{tabb}
   Returns a connection to the database using the properties read from stream \texttt{is}.
   This method loads the properties from the given stream, and
   calls \method{connectToDatabase}{(Properties)} to establish the connection.
\end{tabb}
\begin{htmlonly}
   \param{is}{the stream to read for the properties.}
   \return{the connection to the database.}
   \exception{SQLException}{if the connection failed.}
   \exception{IOException}{if the stream can not be read correctly.}
   \exception{IllegalArgumentException}{if the properties do not contain the require values.}
\end{htmlonly}
\begin{code}

   public static Connection connectToDatabase (URL url)
            throws IOException, SQLException\begin{hide} {
    
      InputStream is = url.openStream();
      try {
         return connectToDatabase (is);
      }
      finally {
         is.close();
      }
   }\end{hide}
\end{code}
\begin{tabb}
   Equivalent to \method{connectToDatabase}{(InputStream)} \texttt{(url.openStream())}.
\end{tabb}
\begin{code}

   public static Connection connectToDatabase (File file)
            throws IOException, SQLException\begin{hide} {
    
      FileInputStream is = new FileInputStream (file);
      try {
         return connectToDatabase (is);
      }
      finally {
         is.close();
      }
   }\end{hide}
\end{code}
\begin{tabb}
   Equivalent to \method{connectToDatabase}{(InputStream)} \texttt{(new FileInputStream (file))}.
\end{tabb}
\begin{code}

   public static Connection connectToDatabase (String fileName)
            throws IOException, SQLException\begin{hide} {

      FileInputStream is = new FileInputStream (fileName);
      try {
         return connectToDatabase (is);
      }
      finally {
         is.close();
      }
   }\end{hide}
\end{code}
\begin{tabb}
   Equivalent to \method{connectToDatabase}{(InputStream)} \texttt{(new FileInputStream (fileName))}.
\end{tabb}
\begin{code}
    
   public static Connection connectToDatabaseFromResource (String resource)
            throws IOException, SQLException\begin{hide} {
        
      InputStream is = JDBCManager.class.getClassLoader().getResourceAsStream (resource);
      try {
         return connectToDatabase (is);
      }
      finally {
         is.close();
      }
   }\end{hide}
\end{code}
\begin{tabb}
   Uses \method{connectToDatabase}{(InputStream)} with the stream obtained from
   the resource \texttt{resource}.
   This method searches the file \texttt{resource} on the class path, opens
   the first resource found, and extracts properties from it.
   It then uses \method{connectToDatabase}{(Properties)}
   to establish the connection.
\end{tabb}
\begin{code}

   public static double[] readDoubleData (Statement stmt, String query)
            throws SQLException\begin{hide} {
      ResultSet rs = stmt.executeQuery (query);
      rs.last();
      double[] res = new double[rs.getRow()];
      rs.first();
        
      for (int i = 0; i < res.length; i++)
      {
         res[i] = rs.getDouble (1);
         rs.next();
      }
      rs.close();
            
      return res;
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into an array of double-precision values.
   This method uses the statement \texttt{stmt} to execute the given query, and
   assumes that the first column of the result set contains double-precision values.
   Each row of the result set then becomes an element of an array of double-precision
   values which is returned by this method.
    This method throws an \class{SQLException} if the query is not valid.
\end{tabb}
\begin{htmlonly}
   \param{stmt}{the statement used to make the query.}
   \param{query}{the SQL query to execute.}
   \return{the first column of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static double[] readDoubleData (Connection connection,
                                          String query)
            throws SQLException\begin{hide} {
      Statement stmt = connection.createStatement
      (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      try {
         return readDoubleData (stmt, query);
      }
      finally {
         stmt.close();
      }
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into an array of double-precision values.
   This method uses the active connection \texttt{connection} to create
   a statement, and passes this statement, with the query, to
   \method{readDoubleData}{(Statement,String)}, which returns an
   array of double-precision values.
\end{tabb}
\begin{htmlonly}
   \param{connection}{the active connection to the database.}
   \param{query}{the SQL query to execute.}
   \return{the first column of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static double[] readDoubleData (Statement stmt, String table,
                                          String column)
            throws SQLException\begin{hide} {
        final String query = "SELECT " + column + " FROM " + table;
        
        return readDoubleData (stmt, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the column \texttt{column} of the table \texttt{table}.
   % in an array of \texttt{double}'s. 
   This method is equivalent to \method{readDoubleData}{(Statement, String)}
   \texttt{(stmt, "SELECT column FROM table")}.
\end{tabb}
\begin{code}

   public static double[] readDoubleData (Connection connection,
                                          String table, String column)
            throws SQLException\begin{hide} {
        final String query = "SELECT " + column + " FROM " + table;
        
        return readDoubleData (connection, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the column \texttt{column} of the table \texttt{table}.
   % in an array of \texttt{double}'s. 
   This method is equivalent to \method{readDoubleData}{(Connection, String)}
   \texttt{(connection, "SELECT column FROM table")}.
\end{tabb}
\begin{code}

   public static int[] readIntData (Statement stmt, String query)
            throws SQLException\begin{hide} {
      ResultSet rs = stmt.executeQuery (query);
      rs.last();
      int[] res = new int[rs.getRow()];
      rs.first();
        
      for (int i = 0; i < res.length; i++)
      {
         res[i] = rs.getInt (1);
         rs.next();
      }
      rs.close();
            
      return res;
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into an array of integers.
   This method uses the statement \texttt{stmt} to execute the given query, and
   assumes that the first column of the result set contains integer values.
   Each row of the result set then becomes an element of an array of integers
    which is returned by this method.
    This method throws an \class{SQLException} if the query is not valid.
   The given statement \texttt{stmt} must not be set up to
   produce forward-only result sets.
\end{tabb}
\begin{htmlonly}
   \param{stmt}{the statement used to make the query.}
   \param{query}{the SQL query to execute.}
   \return{the first column of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static int[] readIntData (Connection connection, String query)
            throws SQLException\begin{hide} {
      Statement stmt = connection.createStatement
      (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      try {
         return readIntData (stmt, query);
      }
      finally {
         stmt.close();
      }
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into an array of integers.
   This method uses the active connection \texttt{connection} to create
   a statement, and passes this statement, with the query, to
   \method{readIntData}{(Statement,String)}, which returns an
   array of integers.
\end{tabb}
\begin{htmlonly}
   \param{connection}{the active connection to the database.}
   \param{query}{the SQL query to execute.}
   \return{the first column of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static int[] readIntData (Statement stmt, String table,
                                    String column)
            throws SQLException\begin{hide} {
        final String query = "SELECT " + column + " FROM " + table;
        
        return readIntData (stmt, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the column \texttt{column} of the table \texttt{table}.
   % in an array of \texttt{int}'s. 
   This method is equivalent to \method{readIntData}{(Statement, String)}
   \texttt{(stmt, "SELECT column FROM table")}.
\end{tabb}
\begin{code}

   public static int[] readIntData (Connection connection, String table,
                                    String column)
            throws SQLException\begin{hide} {
        final String query = "SELECT " + column + " FROM " + table;
        
        return readIntData (connection, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the column \texttt{column} of the table \texttt{table}.
   % in an array of \texttt{int}'s. 
   This method is equivalent to \method{readIntData}{(Connection, String)}
   \texttt{(connection, "SELECT column FROM table")}.
\end{tabb}
\begin{code}

   public static Object[] readObjectData (Statement stmt, String query)
            throws SQLException\begin{hide} {
      ResultSet rs = stmt.executeQuery (query);
      rs.last();
      Object[] res = new Object[rs.getRow()];
      rs.first();
        
      for (int i = 0; i < res.length; i++)
      {
         res[i] = rs.getObject (1);
         rs.next();
      }
      rs.close();
            
      return res;
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into an array of objects.
   This method uses the statement \texttt{stmt} to execute the given query, and
   extracts values from the first column of the obtained result set by
   using the \texttt{getObject} method.
   Each row of the result set then becomes an element of an array of objects
    which is returned by this method.
    The type of the objects in the array depends on the column type of
    the result set, which depends on the database and query.
    This method throws an \class{SQLException} if the query is not valid.
   The given statement \texttt{stmt} must not be set up to
   produce forward-only result sets.
\end{tabb}
\begin{htmlonly}
   \param{stmt}{the statement used to make the query.}
   \param{query}{the SQL query to execute.}
   \return{the first column of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static Object[] readObjectData (Connection connection,
                                          String query)
            throws SQLException\begin{hide} {
      Statement stmt = connection.createStatement
      (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      try {
         return readObjectData (stmt, query);
      }
      finally {
         stmt.close();
      }
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into an array of objects.
   This method uses the active connection \texttt{connection} to create
   a statement, and passes this statement, with the query, to
   \method{readObjectData}{(Statement,String)}, which returns an
   array of integers.
\end{tabb}
\begin{htmlonly}
   \param{connection}{the active connection to the database.}
   \param{query}{the SQL query to execute.}
   \return{the first column of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static Object[] readObjectData (Statement stmt,
                                          String table, String column)
            throws SQLException\begin{hide} {
        final String query = "SELECT " + column + " FROM " + table;
        
        return readObjectData (stmt, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the column \texttt{column} of the table \texttt{table}.
   % in an array of \texttt{int}'s. 
   This method is equivalent to \method{readObjectData}{(Statement, String)}
   \texttt{(stmt, "SELECT column FROM table")}.
\end{tabb}
\begin{code}

   public static Object[] readObjectData (Connection connection,
                                          String table, String column)
            throws SQLException\begin{hide} {
        final String query = "SELECT " + column + " FROM " + table;
        
        return readObjectData (connection, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the column \texttt{column} of the table \texttt{table}.
   % in an array of \texttt{int}'s. 
   This method is equivalent to \method{readObjectData}{(Connection, String)}
   \texttt{(connection, "SELECT column FROM table")}.
\end{tabb}
\begin{code}

   public static double[][] readDoubleData2D (Statement stmt, String query)
            throws SQLException\begin{hide} {
      ResultSet rs = stmt.executeQuery (query);
      rs.last();
      int c = rs.getMetaData().getColumnCount();
      double[][] res = new double[rs.getRow()][c];
      rs.first();
        
      for (int i = 0; i < res.length; i++) {
         for (int j = 0; j < res[i].length; j++)
            res[i][j] = rs.getDouble (1 + j);
         rs.next();
      }
      rs.close();
            
      return res;
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into a
   rectangular 2D array of double-precision values.
   This method uses the statement \texttt{stmt} to execute the given query, and
   assumes that the columns of the result set contain double-precision values.
   Each row of the result set then becomes a row of a 2D array of double-precision
   values which is returned by this method.
    This method throws an \class{SQLException} if the query is not valid.
   The given statement \texttt{stmt} must not be set up to
   produce forward-only result sets.
\end{tabb}
\begin{htmlonly}
   \param{stmt}{the statement used to make the query.}
   \param{query}{the SQL query to execute.}
   \return{the columns of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static double[][] readDoubleData2D (Connection connection,
                                              String query)
            throws SQLException\begin{hide} {
      Statement stmt = connection.createStatement
      (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      try {
         return readDoubleData2D (stmt, query);
      }
      finally {
         stmt.close();
      }
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into a rectangular 2D array
   of double-precision values.
   This method uses the active connection \texttt{connection} to create
   a statement, and passes this statement, with the query, to
   \method{readDoubleData2D}{(Statement,String)}, which returns a 2D
   array of double-precision values.
\end{tabb}
\begin{htmlonly}
   \param{connection}{the active connection to the database.}
   \param{query}{the SQL query to execute.}
   \return{the columns of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static double[][] readDoubleData2DTable (Statement stmt,
                                                   String table)
            throws SQLException\begin{hide} {
        final String query = "SELECT * FROM " + table;
        
        return readDoubleData2D (stmt, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the columns of the table \texttt{table}.
   % in an array of \texttt{double}'s. 
   This method is equivalent to \method{readDoubleData2D}{(Statement, String)}
   \texttt{(stmt, "SELECT * FROM table")}.
\end{tabb}
\begin{code}

   public static double[][] readDoubleData2DTable (Connection connection,
                                                   String table)
            throws SQLException\begin{hide} {
        final String query = "SELECT * FROM " + table;
        
        return readDoubleData2D (connection, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the columns of the table \texttt{table}.
   % in an array of \texttt{double}'s. 
   This method is equivalent to \method{readDoubleData2D}{(Connection, String)}
   \texttt{(connection, "SELECT * FROM table")}.
\end{tabb}
\begin{code}

   public static int[][] readIntData2D (Statement stmt, String query)
            throws SQLException\begin{hide} {
      ResultSet rs = stmt.executeQuery (query);
      rs.last();
      int c = rs.getMetaData().getColumnCount();
      int[][] res = new int[rs.getRow()][c];
      rs.first();
        
      for (int i = 0; i < res.length; i++) {
         for (int j = 0; j < res[i].length; j++)
            res[i][j] = rs.getInt (1 + j);
         rs.next();
      }
      rs.close();
            
      return res;
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into a
   rectangular 2D array of integers.
   This method uses the statement \texttt{stmt} to execute the given query, and
   assumes that the columns of the result set contain integers.
   Each row of the result set then becomes a row of a 2D array of integers
   which is returned by this method.
    This method throws an \class{SQLException} if the query is not valid.
   The given statement \texttt{stmt} must not be set up to
   produce forward-only result sets.
\end{tabb}
\begin{htmlonly}
   \param{stmt}{the statement used to make the query.}
   \param{query}{the SQL query to execute.}
   \return{the columns of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static int[][] readIntData2D (Connection connection, String query)
            throws SQLException\begin{hide} {
      Statement stmt = connection.createStatement
      (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      try {
         return readIntData2D (stmt, query);
      }
      finally {
         stmt.close();
      }
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into a rectangular 2D array
   of integers.
   This method uses the active connection \texttt{connection} to create
   a statement, and passes this statement, with the query, to
   \method{readIntData2D}{(Statement,String)}, which returns a 2D
   array of integers.
\end{tabb}
\begin{htmlonly}
   \param{connection}{the active connection to the database.}
   \param{query}{the SQL query to execute.}
   \return{the columns of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static int[][] readIntData2DTable (Statement stmt, String table)
            throws SQLException\begin{hide} {
        final String query = "SELECT * FROM " + table;
        
        return readIntData2D (stmt, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the columns of the table \texttt{table}.
   % in an array of \texttt{int}'s. 
   This method is equivalent to \method{readIntData2D}{(Statement, String)}
   \texttt{(stmt, "SELECT * FROM table")}.
\end{tabb}
\begin{code}

   public static int[][] readIntData2DTable (Connection connection,
                                             String table)
            throws SQLException\begin{hide} {
        final String query = "SELECT * FROM " + table;
        
        return readIntData2D (connection, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the columns of the table \texttt{table}.
   % in an array of \texttt{int}'s. 
   This method is equivalent to \method{readIntData2D}{(Connection, String)}
   \texttt{(connection, "SELECT * FROM table")}.
\end{tabb}
\begin{code}

   public static Object[][] readObjectData2D (Statement stmt, String query)
            throws SQLException\begin{hide} {
      ResultSet rs = stmt.executeQuery (query);
      rs.last();
      int c = rs.getMetaData().getColumnCount();
      Object[][] res = new Object[rs.getRow()][c];
      rs.first();
        
      for (int i = 0; i < res.length; i++) {
         for (int j = 0; j < res[i].length; j++)
            res[i][j] = rs.getObject (1 + j);
         rs.next();
      }
      rs.close();
            
      return res;
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into a
   rectangular 2D array of objects.
   This method uses the statement \texttt{stmt} to execute the given query, and
   extracts values from the obtained result set by using the \texttt{getObject} method.
   Each row of the result set then becomes a row of a 2D array of objects
   which is returned by this method.
    The type of the objects in the 2D array depends on the column types of
    the result set, which depend on the database and query.
    This method throws an \class{SQLException} if the query is not valid.
   The given statement \texttt{stmt} must not be set up to
   produce forward-only result sets.
\end{tabb}
\begin{htmlonly}
   \param{stmt}{the statement used to make the query.}
   \param{query}{the SQL query to execute.}
   \return{the columns of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static Object[][] readObjectData2D (Connection connection,
                                              String query)
            throws SQLException\begin{hide} {
      Statement stmt = connection.createStatement
      (ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      try {
         return readObjectData2D (stmt, query);
      }
      finally {
         stmt.close();
      }
   }\end{hide}
\end{code}
\begin{tabb}
   Copies the result of the SQL query \texttt{query} into a rectangular 2D array
   of integers.
   This method uses the active connection \texttt{connection} to create
   a statement, and passes this statement, with the query, to
   \method{readObjectData2D}{(Statement,String)}, which returns a 2D
   array of integers.
\end{tabb}
\begin{htmlonly}
   \param{connection}{the active connection to the database.}
   \param{query}{the SQL query to execute.}
   \return{the columns of the result set.}
   \exception{SQLException}{if the query is not valid.}
\end{htmlonly}
\begin{code}

   public static Object[][] readObjectData2DTable (Statement stmt,
                                                   String table)
            throws SQLException\begin{hide} {
        final String query = "SELECT * FROM " + table;
        
        return readObjectData2D (stmt, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the columns of the table \texttt{table}.
   % in an array of \texttt{int}'s. 
   This method is equivalent to \method{readObjectData2D}{(Statement, String)}
   \texttt{(stmt, "SELECT * FROM table")}.
\end{tabb}
\begin{code}

   public static Object[][] readObjectData2DTable (Connection connection,
                                                   String table)
            throws SQLException\begin{hide} {
        final String query = "SELECT * FROM " + table;
        
        return readObjectData2D (connection, query);
    }\end{hide}
\end{code}
\begin{tabb}
   Returns the values of the columns of the table \texttt{table}.
   % in an array of \texttt{int}'s. 
   This method is equivalent to \method{readObjectData2D}{(Connection, String)}
   \texttt{(connection, "SELECT * FROM table")}.
\end{tabb}
\begin{code}\begin{hide}
}\end{hide}
\end{code}
